﻿Namespace Settings

    Public MustInherit Class BaseSetting

        Private mIdent As SettingKey
        Private mName As String
        Private mDesc As String
        Private mUIElement As Control
        Private mNeedsCommit As Boolean = False
        Private mValue As Object
        Private mLastValue As Object

        ' -------------------------------------------------------------------------
        ' Event Definitions
        ' -------------------------------------------------------------------------
        '
        ' This event is fired whenever the Settign value changes
        Public Event ValueChanged(ByVal sender As BaseSetting, ByVal e As SettingEventArgs)

        Public ReadOnly Property ID As SettingKey
            Get
                Return mIdent
            End Get
        End Property

        Public Property Value As Object
            Get
                Return mValue
            End Get
            Set(ByVal value As Object)

                ' Check for possible deserialization 
                If TypeOf value Is String Then
                    value = getValueFromString(value)
                End If

                If Not value.Equals(mValue) Then
                    ' Throws Exception if Fails
                    validateValue(value)
                    Dim old = mValue
                    mValue = value
                    mNeedsCommit = True
                    resetUIElement()
                    onValueChanged(New SettingEventArgs(Me, old))
                End If
            End Set
        End Property

        Public ReadOnly Property Name As String
            Get
                Return mName
            End Get
        End Property

        Public ReadOnly Property Description As String
            Get
                Return mDesc
            End Get
        End Property

        Public ReadOnly Property UIElement As Control
            Get
                If IsNothing(mUIElement) Then
                    mUIElement = getUIElement()
                End If
                Return mUIElement
            End Get
        End Property

        Public ReadOnly Property NeedsCommit As Boolean
            Get
                Return mNeedsCommit
            End Get
        End Property

        Public Sub New(ByVal id As SettingKey,
                       ByVal name As String,
                       ByVal desc As String,
                       ByVal defValue As Object)
            If IsNothing(id) Then
                Throw New ArgumentException("Setting ID cannot be NULL")
            Else
                mIdent = id
                mName = name
                mDesc = desc
                If TypeOf defValue Is String Then
                    defValue = getValueFromString(defValue)
                End If
                mValue = defValue
                mLastValue = defValue
            End If
        End Sub

        Friend Sub quietSet(ByVal strValue As String)
            Dim value As Object = getValueFromString(strValue)
            Try
                validateValue(value)
                mValue = value
            Catch ex As ArgumentOutOfRangeException
                Throw ex
            End Try

        End Sub

        Friend Sub commit()
            If Me.NeedsCommit Then
                Debug.WriteLine("Setting [" & Me.Name & "] Committing: New=" & mValue & "  (Old =" & mLastValue & ")")
                mLastValue = mValue
                mNeedsCommit = False
            End If
        End Sub

        Friend Sub rollback()
            mValue = mLastValue
            resetUIElement()
            mNeedsCommit = False
        End Sub

        ''' <summary>
        ''' Handles the firing of the internal event to any Listeners.
        ''' </summary>
        ''' <param name="e"></param>
        ''' <remarks></remarks>
        Private Sub onValueChanged(ByVal e As EventArgs)
            RaiseEvent ValueChanged(Me, e)
        End Sub

        Friend Overridable Function valueAsString() As String
            Return mValue.ToString
        End Function

        Protected MustOverride Function getUIElement() As Control

        Protected MustOverride Sub resetUIElement()

        ''' <summary>
        ''' Performs input validation on the value 
        ''' </summary>
        ''' <param name="value"></param>
        ''' <remarks>This method MUST throw an ArgumentOutOfRangeException
        ''' if validation fails.</remarks>
        Protected MustOverride Sub validateValue(ByVal value As Object)

        Protected MustOverride Function getValueFromString(ByVal value As String) As Object

    End Class

End Namespace

